using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;

namespace SteeringBehaviors
{
    public class Ship : MovingObject
    {
        #region PRIVATE MEMBERS

        static Random rand = new Random();
        bool idle;
        float armor;
        float shield;
        float maxShield;
        float shieldRegeneration;
        float energy;
        float maxEnergy;
        float energyRegeneration;
        float taskForceSpeed;
        float maxSpeed;
        float acceleration;
        uint maxCargo;
        uint cargo;

        #endregion

        #region PROPERTIES

        /// <summary>
        /// Is this ship performing any ship specific actions? (i.e. Fighting or Minning)
        /// </summary>
        public bool Idle
        {
            get { return idle; }
            set { idle = value; }
        }

        /// <summary>
        /// Health of this ship; when this reaches zero or lower the ship is destroyed.
        /// </summary>
        public float Armor
        {
            get { return armor; }
            set { armor = value; }
        }

        /// <summary>
        /// Shielding value of this ship; shields recharge automatically and are usually damaged before armor.
        /// </summary>
        public float Shield
        {
            get { return shield; }
            set 
            {
                if (value < MaxShield && value >= 0)
                    shield = value;
                else if (value < 0)
                    shield = 0;
                else
                    shield = MaxShield;
            }
        }

        /// <summary>
        /// The maximum shielding value that this ship can support.  Shields will not recharged beyond this value.
        /// </summary>
        public float MaxShield
        {
            get { return maxShield; }
            set { maxShield = value; }
        }

        /// <summary>
        /// The amount of shield units per second gained until max is reached.
        /// </summary>
        public float ShieldRegeneration
        {
            get { return shieldRegeneration; }
            set { shieldRegeneration = value; }
        }

        /// <summary>
        /// Energy reserves for use in various skills.
        /// </summary>
        public float Energy
        {
            get { return energy; }
            set 
            {
                if (value < MaxEnergy && value >= 0)
                    energy = value;
                else if (value < 0)
                    energy = 0;
                else
                    energy = MaxEnergy;
            }
        }

        /// <summary>
        /// Maximum energy this ship can support.  Energy will not be recharged beyond this value.
        /// </summary>
        public float MaxEnergy
        {
            get { return maxEnergy; }
            set { maxEnergy = value; }
        }

        /// <summary>
        /// The amount of energy units per second gained until max is reached.
        /// </summary>
        public float EnergyRegeneration
        {
            get { return energyRegeneration; }
            set { energyRegeneration = value; }
        }

        /// <summary>
        /// The magnitude of velocity this ship will adhere to for its current task force
        /// </summary>
        public float TaskForceSpeed
        {
            get { return taskForceSpeed; }
            set
            {
                if (value <= MaxSpeed && value > 0)
                    taskForceSpeed = value;
                else
                    taskForceSpeed = MaxSpeed;
            }
        }

        /// <summary>
        /// Maximum magnitude of velocity for this ship.
        /// </summary>
        public float MaxSpeed
        {
            get { return maxSpeed; }
            set { maxSpeed = value; }
        }

        /// <summary>
        /// percentage (0.0f - 1.0f) of MaxSpeed to serve as magnitude of acceleration/decceleration
        /// </summary>
        public float Acceleration
        {
            get { return acceleration; }
            set
            {
                if (value < 0)
                    acceleration = 0;
                else if (value > 1f)
                    acceleration = 1f;
                else
                    acceleration = value;
            }
        }

        /// <summary>
        /// Current amount of minerals this ship is carrying.
        /// </summary>
        public uint Cargo
        {
            get { return cargo; }
            set 
            {
                if (MaxCargo == 0 || value < MaxCargo)
                    cargo = value;
                else
                    cargo = MaxCargo;
            }
        }

        /// <summary>
        /// Maximum amount of resources this ship can carry.
        /// Note: a value of zero means infinite.
        /// </summary>
        public uint MaxCargo
        {
            get { return maxCargo; }
            set { maxCargo = value; }
        }

        #endregion

        #region CONSTRUCTORS

        public Ship()
        {
            Type = "Ship";
            Armor = 1;
            Shield = MaxShield = 0;
            Energy = MaxEnergy = 0;
            Cargo = MaxCargo = 0;
            MaxSpeed = 25f;
            TaskForceSpeed = 25f;
            Idle = true;
            Acceleration = .5f;
            Vector3 randVelocity = new Vector3(Convert.ToSingle(rand.NextDouble()) - .5f,
                Convert.ToSingle(rand.NextDouble()) - .5f, 0f);
            randVelocity.Normalize();
            Velocity = randVelocity;
        }

        #endregion

        #region INTERFACE METHODS

        /// <summary>
        /// Gets a string representation of this ship.
        /// </summary>
        /// <returns>a string representation of this ship</returns>
        public override string ToString()
        {
            return "ID:" + ID + " Type:" + Type;
            //return base.ToString();
        }

        /// <summary>
        /// Regulates velocity and updates the ship's position.
        /// </summary>
        /// <param name="_delta">seconds since last update</param>
        public override void Update(float _delta)
        {
            if (MaxShield != 0 && Shield < MaxShield)
            {
                Shield += ShieldRegeneration * _delta;
            }
            if (MaxEnergy != 0 && Energy < MaxEnergy)
            {
                Energy += EnergyRegeneration * _delta;
            }
            // force ships within maxspeed
            if (Velocity.LengthSq() > TaskForceSpeed * TaskForceSpeed)
            {
                Vector3 vel = new Vector3();
                vel = Velocity;
                vel.Normalize();
                vel.Scale(TaskForceSpeed);
                Velocity = vel;
            }
            base.Update(_delta);
        }

        /// <summary>
        /// Deals the specified damage to this ship.  Damage is delt
        /// to shields first unless the bypassShields parameter is
        /// true.
        /// </summary>
        /// <param name="_damage">the amount of damage to deal</param>
        /// <param name="bypassShields">true = skip shields when applying damage</param>
        public void RecieveDamage(float _damage, bool _bypassShields)
        {
            if (!_bypassShields)
            {
                if (_damage > Shield)
                {
                    _damage -= Shield;
                    Shield = 0;
                }
                else
                {
                    Shield -= _damage;
                }
            }
            if (_damage > Armor)
            {
                Armor = 0;
            }
            else
            {
                Armor -= _damage;
            }
        }

        public Ship Clone()
        {
            Ship retval = new Ship();
            uint id = retval.ID;
            retval = (Ship)this.MemberwiseClone();
            retval.ID = id;
            return retval;
        }

        #endregion
    }
}
